using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using GTA;
using GTA.Native;

namespace CustomPeds;

[Serializable]
public class Skin
{
	public enum PedComponents
	{
		FACE,
		HEAD,
		HAIR,
		TORSO,
		LEGS,
		HANDS,
		FEET,
		ACCESSORIES,
		TORSO3,
		TASKS,
		TEXTURES,
		TORSO2
	}

	public enum PedProps
	{
		HATS = 0,
		GLASSES = 1,
		EARRINGS = 2,
		WristAccessories1 = 6,
		WristAccessories2 = 7
	}

	public enum PedHeadOverlay
	{
		Blemishes,
		Beard,
		Eyebrows,
		Ageing,
		Makeup,
		Blush,
		SunDamage,
		Skin,
		Lipstick,
		MolesFreckles,
		ChestHair,
		BodyBlemishes,
		DenseBodyBlemishes
	}

	public enum HeadOverlayColorType
	{
		Default,
		Colors1,
		Colors2,
		NoColor
	}

	public enum PedFaceFeature
	{
		NoseWidth,
		NoseHeight,
		NoseDepth,
		NoseRidge,
		NoseTip,
		NoseBroken,
		BrowHeight,
		BrowDepth,
		CheekboneHeight,
		CheekboneOut,
		CheekPlumpness,
		EyeSize,
		LipSize,
		JawWidth,
		JawRounded,
		ChinHeight,
		ChinOut,
		ChinPointy,
		ChinIndent,
		NeckWidth
	}

	public struct Component
	{
		public int drawableId;

		public int textureId;

		public int paletteId;

		[XmlIgnore]
		public int drawableNumber;

		public bool action;
	}

	public struct Prop
	{
		public int drawableId;

		public int textureId;

		[XmlIgnore]
		public int drawableNumber;

		public bool attach;

		public bool action;
	}

	public struct HeadOverlay
	{
		[XmlIgnore]
		public int overlayNumber;

		public int overlayValue;

		public float opacity;

		public int colorType;

		public int firstColor;

		public int secondColor;

		public bool overlayAction;

		public bool colorAction;
	}

	public struct OtherColors
	{
		public int eyeColorId;

		public int hairColorId;

		public int hairHighlightColorID;

		public bool eyeAction;

		public bool hairAction;
	}

	public struct HeadBlend
	{
		[XmlIgnore]
		public int faceNumber;

		public int shapeFirstID;

		public int shapeSecondID;

		public int shapeThirdID;

		public int skinFirstID;

		public int skinSecondID;

		public int skinThirdID;

		public float shapeMix;

		public float skinMix;

		public float thirdMix;

		public bool isParent;

		public bool action;
	}

	public struct FaceFeature
	{
		public float featureValue;

		public bool action;
	}

	public struct WeaponData
	{
		public uint weaponHash;

		public bool InUse;

		public int tint;

		public int ammo;

		public int ammoInClip;

		public int maxComponents;

		public List<uint> weaponComponent;
	}

	public struct Tattoos
	{
		public string collectionName;

		public string overlayName;

		public bool action;
	}

	public struct Badges
	{
		public string collectionName;

		public string overlayName;

		public bool action;
	}

	public static readonly string[] FEMALE_NAME = new string[177]
	{
		"Abigail", "AbigailCutscene", "Airhostess01SFY", "AmandaTownley", "AmandaTownleyCutscene", "AnitaCutscene", "Ashley", "AshleyCutscene", "Ballas01GFY", "Bartender01SFY",
		"Baywatch01SFY", "Beach01AFM", "Beach01AFY", "Bevhills01AFM", "Bevhills01AFY", "Bevhills02AFM", "Bevhills02AFY", "Bevhills03AFY", "Bevhills04AFY", "BikerChic",
		"BoatStaff01F", "Bride", "BrideCutscene", "Business01AFY", "Business02AFM", "Business02AFY", "Business03AFY", "Business04AFY", "CarDesignFemale01", "ClubHouseBar01",
		"CocaineFemale01", "ComJane", "Corpse01", "Corpse01UFY", "Corpse02", "CounterfeitFemale01", "DeadHooker", "DebraCutscene", "Denise", "DeniseCutscene",
		"DeniseFriendCutscene", "Downtown01AFM", "Drowned", "Eastsa01AFM", "Eastsa01AFY", "Eastsa02AFM", "Eastsa02AFY", "Eastsa03AFY", "Epsilon01AFY", "ExecutivePAFemale01",
		"ExecutivePAFemale02", "Factory01SFY", "Families01GFY", "FatBla01AFM", "FatCult01AFM", "FatWhite01AFM", "FemaleAgent", "FemBarberSFM", "Fitness01AFY", "Fitness02AFY",
		"ForgeryFemale01", "FreemodeFemale01", "Genhot01AFY", "Genstreet01AFO", "Golfer01AFY", "GuadalopeCutscene", "GurkCutscene", "HeliStaff01", "Hiker01AFY", "Hippie01AFY",
		"Hipster01AFY", "Hipster02AFY", "Hipster03AFY", "Hipster04AFY", "Hooker01SFY", "Hooker02SFY", "Hooker03SFY", "Hotposh01", "ImportExportFemale01", "Indian01AFO",
		"Indian01AFY", "Janet", "JanetCutscene", "Jewelass", "Jewelass01", "JewelassCutscene", "Juggalo01AFY", "KarenDaniels", "KarenDanielsCutscene", "KerryMcintosh",
		"Ktown01AFM", "Ktown01AFO", "Ktown02AFM", "Lost01GFY", "Magenta", "MagentaCutscene", "Maid01SFM", "Marnie", "MarnieCutscene", "MaryAnn",
		"MaryannCutscene", "Maude", "MaudeCutscene", "MethFemale01", "Michelle", "MichelleCutscene", "Migrant01SFY", "Miranda", "Mistress", "Molly",
		"MollyCutscene", "MoviePremFemaleCutscene", "MovieStar", "MovPrem01SFY", "MrsPhillips", "MrsPhillipsCutscene", "MrsThornhill", "MrsThornhillCutscene", "Natalia", "NataliaCutscene",
		"Patricia", "PatriciaCutscene", "Poppymich", "Princess", "PrologueHostage01", "PrologueHostage01AFM", "PrologueMournFemale01", "Ranger01SFY", "Runner01AFY", "Rurmeth01AFY",
		"Salton01AFM", "Salton01AFO", "Scdressy01AFY", "ScreenWriter", "ScreenWriterCutscene", "Scrubs01SFY", "ShopHighSFM", "ShopLowSFY", "ShopMidSFY", "Skater01AFY",
		"Skidrow01AFM", "Soucent01AFM", "Soucent01AFO", "Soucent01AFY", "Soucent02AFO", "Soucent02AFY", "Soucent03AFY", "Soucentmc01AFM", "SpyActress", "Stripper01Cutscene",
		"Stripper01SFY", "Stripper02Cutscene", "Stripper02SFY", "StripperLite", "StripperLiteSFY", "Sweatshop01SFM", "Sweatshop01SFY", "Tanisha", "TanishaCutscene", "Tennis01AFY",
		"Tonya", "TonyaCutscene", "Topless01AFY", "Tourist01AFM", "Tourist01AFY", "Tourist02AFY", "TracyDisanto", "TracyDisantoCutscene", "Tramp01AFM", "TrampBeac01AFM",
		"Vagos01GFY", "Vinewood01AFY", "Vinewood02AFY", "Vinewood03AFY", "Vinewood04AFY", "WeedFemale01", "Yoga01AFY"
	};

	public static readonly string[] MALE_NAME = new string[528]
	{
		"Abner", "Acult01AMM", "Acult01AMO", "Acult01AMY", "Acult02AMO", "Acult02AMY", "AfriAmer01AMM", "Agent", "Agent14", "Agent14Cutscene",
		"AgentCutscene", "AirworkerSMY", "AlDiNapoli", "Ammucity01SMY", "AmmuCountrySMM", "Andreas", "AndreasCutscene", "Antonb", "AntonCutscene", "ArmBoss01GMM",
		"ArmGoon01GMM", "ArmGoon02GMY", "ArmLieut01GMM", "Armoured01", "Armoured01SMM", "Armoured02SMM", "Armymech01SMY", "Autopsy01SMY", "Autoshop01SMM", "Autoshop02SMM",
		"AviSchwartzman", "AviSchwartzmanCutscene", "Azteca01GMY", "Babyd", "BallaEast01GMY", "BallaOrig01GMY", "Ballasog", "BallasogCutscene", "BallaSout01GMY", "Bankman",
		"Bankman01", "BankmanCutscene", "Barman01SMY", "Barry", "BarryCutscene", "Baygor", "Baywatch01SMY", "Beach01AMM", "Beach01AMO", "Beach01AMY",
		"Beach02AMM", "Beach02AMY", "Beach03AMY", "Beachvesp01AMY", "Beachvesp02AMY", "Benny", "Bestmen", "Beverly", "BeverlyCutscene", "Bevhills01AMM",
		"Bevhills01AMY", "Bevhills02AMM", "Bevhills02AMY", "BikeHire01", "Blackops01SMY", "Blackops02SMY", "Blackops03SMY", "BoatStaff01M", "Bodybuild01AFM", "Bouncer01SMM",
		"Brad", "BradCadaverCutscene", "BradCutscene", "Breakdance01AMY", "BurgerDrug", "BurgerDrugCutscene", "Busboy01SMY", "Busicas01AMY", "Business01AMM", "Business01AMY",
		"Business02AMY", "Business03AMY", "Busker01SMO", "Car3Guy1", "Car3Guy1Cutscene", "Car3Guy2", "Car3Guy2Cutscene", "CarBuyerCutscene", "Casey", "CaseyCutscene",
		"CCrew01SMM", "Chef", "Chef01SMY", "Chef2", "Chef2Cutscene", "ChefCutscene", "ChemSec01SMM", "ChemWork01GMM", "ChiBoss01GMM", "ChiCold01GMM",
		"ChiGoon01GMM", "ChiGoon02GMM", "ChinGoonCutscene", "Chip", "CiaSec01SMM", "Claude01", "Clay", "ClayCutscene", "Claypain", "Cletus",
		"CletusCutscene", "Clown01SMY", "Cntrybar01SMM", "CocaineMale01", "Construct01SMY", "Construct02SMY", "Cop01SFY", "Cop01SMY", "CopCutscene", "CounterfeitMale01",
		"CrisFormage", "CrisFormageCutscene", "CustomerCutscene", "Cyclist01", "Cyclist01AMY", "Dale", "DaleCutscene", "DaveNorton", "DaveNortonCutscene", "Dealer01SMY",
		"Devin", "DevinCutscene", "Devinsec01SMY", "Dhill01AMY", "DoaMan", "Dockwork01SMM", "Dockwork01SMY", "Doctor01SMM", "Dom", "DomCutscene",
		"Doorman01SMY", "Downtown01AMY", "Dreyfuss", "DreyfussCutscene", "DrFriedlander", "DrFriedlanderCutscene", "DwService01SMY", "DwService02SMY", "Eastsa01AMM", "Eastsa01AMY",
		"Eastsa02AM", "Eastsa02AMM", "EdToh", "Epsilon01AMY", "Epsilon02AMY", "ExArmy01", "ExecutivePAMale01", "Fabien", "FabienCutscene", "Factory01SMY",
		"Famca01GMY", "Famdd01", "Famdnf01GMY", "Famfor01GMY", "Farmer01AMM", "Fatlatin01AMM", "FbiSuit01", "FbiSuit01Cutscene", "FibArchitect", "FibMugger01",
		"FibOffice01SMM", "FibOffice02SMM", "FibSec01", "FibSec01SMM", "FilmDirector", "FilmNoir", "Finguru01", "Fireman01SMY", "Floyd", "FloydCutscene",
		"ForgeryMale01", "FosRepCutscene", "Franklin", "FreemodeMale01", "G", "Gaffer01SMM", "GarbageSMY", "Gardener01SMM", "Gay01AMY", "Gay02AMY",
		"GCutscene", "Genfat01AMM", "Genfat02AMM", "Genstreet01AMO", "Genstreet01AMY", "Genstreet02AMY", "GentransportSMM", "Glenstank01", "Golfer01AMM", "Golfer01AMY",
		"Griff01", "Grip01SMY", "Groom", "GroomCutscene", "GroveStrDlrCutscene", "Guido01", "GunVend01", "Hacker", "Hairdress01SMM", "Hao",
		"HaoCutscene", "Hasjew01AMM", "Hasjew01AMY", "Highsec01SMM", "Highsec02SMM", "Hiker01AMY", "Hillbilly01AMM", "Hillbilly02AMM", "Hippie01", "Hippy01AMY",
		"Hipster01AMY", "Hipster02AMY", "Hipster03AMY", "HughCutscene", "Hunter", "HunterCutscene", "Hwaycop01SMY", "Imporage", "ImportExportMale01", "ImranCutscene",
		"Indian01AMM", "Indian01AMY", "JackHowitzerCutscene", "JanitorCutscene", "JanitorSMM", "JayNorris", "Jesus01", "Jetski01AMY", "JewelSec01", "JewelThief",
		"JimmyBoston", "JimmyBostonCutscene", "JimmyDisanto", "JimmyDisantoCutscene", "JoeMinuteman", "JoeMinutemanCutscene", "JohnnyKlebitz", "JohnnyKlebitzCutscene", "Josef", "JosefCutscene",
		"Josh", "JoshCutscene", "Juggalo01AMY", "Justin", "KorBoss01GMM", "Korean01GMY", "Korean02GMY", "KorLieut01GMY", "Ktown01AMM", "Ktown01AMO",
		"Ktown01AMY", "Ktown02AMY", "LamarDavis", "LamarDavisCutscene", "Lathandy01SMM", "Latino01AMY", "Lazlow", "LazlowCutscene", "LesterCrest", "LesterCrestCutscene",
		"Lifeinvad01", "Lifeinvad01Cutscene", "Lifeinvad01SMM", "Lifeinvad02", "LinecookSMM", "Lost01GMY", "Lost02GMY", "Lost03GMY", "Lsmetro01SMM", "Malc",
		"Malibu01AMM", "Mani", "Manuel", "ManuelCutscene", "Mariachi01SMM", "Marine01SMM", "Marine01SMY", "Marine02SMM", "Marine02SMY", "Marine03SMY",
		"Markfost", "Marston01", "MartinMadrazoCutscene", "MerryWeatherCutscene", "Methhead01AMY", "MethMale01", "MexBoss01GMM", "MexBoss02GMM", "MexCntry01AMM", "MexGang01GMY",
		"MexGoon01GMY", "MexGoon02GMY", "MexGoon03GMY", "MexLabor01AMM", "MexThug01AMY", "Michael", "Migrant01SMM", "MilitaryBum", "Milton", "MiltonCutscene",
		"MimeSMY", "Misty01", "Motox01AMY", "Motox02AMY", "MovAlien01", "MoviePremMaleCutscene", "Movprem01SMM", "Movspace01SMM", "MPros01", "MrK",
		"MrKCutscene", "Musclbeac01AMY", "Musclbeac02AMY", "NervousRon", "NervousRonCutscene", "Nigel", "NigelCutscene", "Niko01", "OgBoss01AMM", "OldMan1a",
		"OldMan1aCutscene", "OldMan2", "OldMan2Cutscene", "Omega", "OmegaCutscene", "ONeil", "Orleans", "OrleansCutscene", "Ortega", "OrtegaCutscene",
		"OscarCutscene", "Paige", "PaigeCutscene", "Paparazzi", "Paparazzi01AMM", "Paper", "PaperCutscene", "Paramedic01SMM", "Party01", "PartyTarget",
		"PestCont01SMY", "PestContDriver", "PestContGunman", "Pilot01SMM", "Pilot01SMY", "Pilot02SMM", "Pogo01", "PoloGoon01GMY", "PoloGoon02GMY", "Polynesian01AMM",
		"Polynesian01AMY", "Popov", "PopovCutscene", "PornDudesCutscene", "Postal01SMM", "Postal02SMM", "Priest", "PriestCutscene", "Prisguard01SMM", "PrisMuscl01SMY",
		"Prisoner01", "Prisoner01SMY", "PrologueDriver", "PrologueDriverCutscene", "PrologueHostage01AMM", "PrologueMournMale01", "PrologueSec01", "PrologueSec01Cutscene", "PrologueSec02", "PrologueSec02Cutscene",
		"RampGang", "RampGangCutscene", "RampHic", "RampHicCutscene", "RampHipster", "RampHipsterCutscene", "RampMarineCutscene", "RampMex", "RampMexCutscene", "Ranger01SMY",
		"Rashkovsky", "RashkovskyCutscene", "ReporterCutscene", "RivalPaparazzi", "Roadcyc01AMY", "Robber01SMY", "RoccoPelosi", "RoccoPelosiCutscene", "RsRanger01AMO", "Runner01AMY",
		"Runner02AMY", "Rurmeth01AMM", "RussianDrunk", "RussianDrunkCutscene", "Salton01AMM", "Salton01AMO", "Salton01AMY", "Salton02AMM", "Salton03AMM", "Salton04AMM",
		"SalvaBoss01GMY", "SalvaGoon01GMY", "SalvaGoon02GMY", "SalvaGoon03GMY", "SbikeAMO", "Scientist01SMM", "Security01SMM", "SecuroGuardMale01", "Sheriff01SFY", "Sheriff01SMY",
		"ShopKeep01", "ShopMaskSMY", "SiemonYetarian", "SiemonYetarianCutscene", "Skater01AMM", "Skater01AMY", "Skater02AMY", "Skidrow01AMM", "SlodHuman", "SlodLargeQuadped",
		"SlodSmallQuadped", "SmugMech01", "Snowcop01SMM", "Socenlat01AMM", "Solomon", "SolomonCutscene", "Soucent01AMM", "Soucent01AMO", "Soucent01AMY", "Soucent02AFM",
		"Soucent02AMM", "Soucent02AMO", "Soucent02AMY", "Soucent03AMM", "Soucent03AMO", "Soucent03AMY", "Soucent04AMM", "Soucent04AMY", "SpyActor", "Staggrm01AMO",
		"Stbla01AMY", "Stbla02AMY", "SteveHains", "SteveHainsCutscene", "Stlat01AMY", "Stlat02AMM", "StreetArt01", "Stretch", "StretchCutscene", "Strperf01SMM",
		"Strpreach01SMM", "StrPunk01GMY", "StrPunk02GMY", "Strvend01SMM", "Strvend01SMY", "Stwhi01AMY", "Stwhi02AMY", "Sunbathe01AMY", "Surfer01AMY", "Swat01SMY",
		"Talina", "TaoCheng", "TaoChengCutscene", "TaosTranslator", "TaosTranslatorCutscene", "Taphillbilly", "Tattoo01AMO", "Tennis01AMM", "TennisCoach", "TennisCoachCutscene",
		"Terry", "TerryCutscene", "TomCutscene", "TomEpsilon", "TomEpsilonCutscene", "Tourist01AMM", "TrafficWarden", "TrafficWardenCutscene", "Tramp01", "Tramp01AMM",
		"Tramp01AMO", "TrampBeac01AMM", "Tranvest01AMM", "Tranvest02AMM", "Trevor", "Trucker01SMM", "TylerDixon", "UndercoverCopCutscene", "Ups01SMM", "Ups02SMM",
		"Uscg01SMY", "VagosFun01", "VagosSpeak", "VagosSpeakCutscene", "Valet01SMY", "Vindouche01AMY", "Vinewood01AMY", "Vinewood02AMY", "Vinewood03AMY", "Vinewood04AMY",
		"Wade", "WadeCutscene", "Waiter01SMY", "WareMechMale01", "WeaponExpertMale01", "WeaponWorkerMale01", "WeedMale01", "WeiCheng", "WeiChengCutscene", "WillyFist",
		"WinClean01SMY", "Xmech01SMY", "Xmech02SMY", "Xmech02SMYMP", "Yoga01AMY", "Zimbor", "ZimborCutscene", "Zombie01"
	};

	public static readonly string[] PLAYER_NAME = new string[3] { "Michael", "Franklin", "Trevor" };

	public static readonly string[] FREEMODE_NAME = new string[2] { "FreemodeFemale01", "FreemodeMale01" };

	public static readonly string[] COP_NAME = new string[11]
	{
		"Cop01SFY", "Cop01SMY", "FibSec01", "FibSec01SMM", "Hwaycop01SMY", "Ranger01SMY", "Sheriff01SFY", "Sheriff01SMY", "Snowcop01SMM", "Swat01SMY",
		"Uscg01SMY"
	};

	public static readonly string[] LSFD_PARAMEDIC_NAME = new string[2] { "Fireman01SMY", "Paramedic01SMM" };

	public static readonly string[] ARMY_NAME = new string[7] { "Armymech01SMY", "Autopsy01SMY", "Marine01SMM", "Marine01SMY", "Marine02SMM", "Marine02SMY", "Marine03SMY" };

	public static readonly string[] NONHUMAN_NAME = new string[32]
	{
		"Boar", "Cat", "ChickenHawk", "Chimp", "Chop", "Cormorant", "Cow", "Coyote", "Crow", "Deer",
		"Dolphin", "Fish", "HammerShark", "Hen", "Humpback", "Husky", "KillerWhale", "MountainLion", "Pig", "Pigeon",
		"Poodle", "Pug", "Rabbit", "Rat", "Retriever", "Rhesus", "Rottweiler", "Seagull", "Shepherd", "Stingray",
		"TigerShark", "Westy"
	};

	public static readonly string[] FACE_FEATURE = new string[20]
	{
		TextSetting.ffs_ListItem_NoseWidth,
		TextSetting.ffs_ListItem_NoseHeight,
		TextSetting.ffs_ListItem_NoseDepth,
		TextSetting.ffs_ListItem_NoseRidge,
		TextSetting.ffs_ListItem_NoseTip,
		TextSetting.ffs_ListItem_NoseBroken,
		TextSetting.ffs_ListItem_BrowHeight,
		TextSetting.ffs_ListItem_BrowDepth,
		TextSetting.ffs_ListItem_CheekboneHeight,
		TextSetting.ffs_ListItem_CheekboneOut,
		TextSetting.ffs_ListItem_CheekPlumpness,
		TextSetting.ffs_ListItem_EyeSize,
		TextSetting.ffs_ListItem_LipSize,
		TextSetting.ffs_ListItem_JawWidth,
		TextSetting.ffs_ListItem_JawRounded,
		TextSetting.ffs_ListItem_ChinHeight,
		TextSetting.ffs_ListItem_ChinOut,
		TextSetting.ffs_ListItem_ChinPointy,
		TextSetting.ffs_ListItem_ChinIndent,
		TextSetting.ffs_ListItem_NeckWidth
	};

	public static readonly string SKIN_PATH = "scripts\\CustomPeds\\Skin";

	public static readonly string[] FEMALE_VOICE_NAME = new string[19]
	{
		"s_f_y_hooker_01_white_full_01", "s_f_y_hooker_01_white_full_02", "s_f_y_hooker_01_white_full_03", "s_f_y_hooker_02_white_full_01", "s_f_y_hooker_02_white_full_02", "s_f_y_hooker_02_white_full_03", "s_f_y_hooker_03_black_full_01", "s_f_y_hooker_03_black_full_03", "s_f_m_genericcheapworker_01_latino_mini_01", "s_f_m_genericcheapworker_01_latino_mini_02",
		"s_f_m_genericcheapworker_01_latino_mini_03", "s_f_y_genericcheapworker_01_black_mini_01", "s_f_y_genericcheapworker_01_black_mini_02", "s_f_y_genericcheapworker_01_latino_mini_01", "s_f_y_genericcheapworker_01_latino_mini_02", "s_f_y_genericcheapworker_01_latino_mini_03", "s_f_y_genericcheapworker_01_latino_mini_04", "s_f_y_genericcheapworker_01_white_mini_01", "s_f_y_genericcheapworker_01_white_mini_02"
	};

	public static readonly string[] MALE_VOICE_NAME = new string[29]
	{
		"a_m_m_genericmale_01_white_mini_01", "a_m_m_genericmale_01_white_mini_02", "a_m_m_genericmale_01_white_mini_03", "a_m_m_genericmale_01_white_mini_04", "s_m_m_genericcheapworker_01_latino_mini_01", "s_m_m_genericcheapworker_01_latino_mini_02", "s_m_m_genericcheapworker_01_latino_mini_03", "s_m_m_genericcheapworker_01_latino_mini_04", "s_m_m_genericmarine_01_latino_mini_01", "s_m_m_genericmarine_01_latino_mini_02",
		"s_m_m_genericmechanic_01_black_mini_01", "s_m_m_genericmechanic_01_black_mini_02", "s_m_m_genericpostworker_01_black_mini_01", "s_m_m_genericpostworker_01_black_mini_02", "s_m_m_genericpostworker_01_white_mini_01", "s_m_m_genericpostworker_01_white_mini_02", "s_m_y_genericcheapworker_01_black_mini_01", "s_m_y_genericcheapworker_01_black_mini_02", "s_m_y_genericcheapworker_01_white_mini_01", "s_m_y_genericmarine_01_black_mini_01",
		"s_m_y_genericmarine_01_black_mini_02", "s_m_y_genericmarine_01_white_mini_01", "s_m_y_genericmarine_01_white_mini_02", "s_m_y_genericworker_01_black_mini_01", "s_m_y_genericworker_01_black_mini_02", "s_m_y_genericworker_01_latino_mini_01", "s_m_y_genericworker_01_latino_mini_02", "s_m_y_genericworker_01_white_mini_01", "s_m_y_genericworker_01_white_mini_02"
	};

	public static readonly int[] HEAD_OVERLAY_CAN_EDIT_COLOR = new int[6] { 1, 2, 4, 5, 8, 10 };

	public static readonly int HEAD_OVERLAY_COLOR_NUM = 64;

	public static readonly int OTHER_COLOR_HAIR_NUM = 64;

	public static readonly int OTHER_COLOR_EYE_NUM = 32;

	public Component[] Components = new Component[12];

	public Prop[] Props = new Prop[8];

	public HeadOverlay[] Head_Overlay = new HeadOverlay[13];

	public HeadBlend Head_Blend;

	public OtherColors Other_Colors;

	public FaceFeature[] Face_Feature = new FaceFeature[20];

	public Tattoos[][] Tattoo = new Tattoos[6][];

	public Badges[][] Badge = new Badges[6][];

	[XmlIgnore]
	public List<WeaponData> Weaponry;

	[XmlIgnore]
	public int[][] ComponentsTextureData = new int[12][];

	[XmlIgnore]
	public int[][] PropsTextureData = new int[8][];

	[XmlIgnore]
	public List<Decoration.Collection>[] TattooData;

	[XmlIgnore]
	public List<Decoration.Collection>[] BadgeData;

	public string ModelName;

	public string Gender;

	public string Voice;

	public bool IsAddonPed;

	private Ped Character;

	public Skin()
	{
	}

	public Skin(Ped _character, bool isAddonPed)
	{
		Character = _character;
		Gender = Character.Gender.ToString();
		Voice = string.Empty;
		IsAddonPed = isAddonPed;
		ModelName = Origin.GetPedModelName(Character.Model);
		for (int i = 0; i < 6; i++)
		{
			Tattoo[i] = new Tattoos[4];
			Badge[i] = new Badges[4];
			for (int j = 0; j < 4; j++)
			{
				Tattoo[i][j] = default(Tattoos);
				Badge[i][j] = default(Badges);
			}
		}
	}

	public static bool SkinFileSave(Origin origin, string name, string fullName = "")
	{
		try
		{
			if (fullName == "")
			{
				if (!MakeFilenameValid(ref name))
				{
					return false;
				}
				XmlSerializer xmlSerializer = new XmlSerializer(origin.skin.GetType());
				using XmlTextWriter xmlTextWriter = new XmlTextWriter($"{SKIN_PATH}\\{origin.skin.Gender}\\{name}.skin", Encoding.UTF8);
				xmlTextWriter.Formatting = Formatting.Indented;
				xmlSerializer.Serialize(xmlTextWriter, origin.skin);
			}
			else
			{
				File.Delete(fullName);
				XmlSerializer xmlSerializer2 = new XmlSerializer(origin.skin.GetType());
				using XmlTextWriter xmlTextWriter2 = new XmlTextWriter($"{SKIN_PATH}\\{origin.skin.Gender}\\{name}.skin", Encoding.UTF8);
				xmlTextWriter2.Formatting = Formatting.Indented;
				xmlSerializer2.Serialize(xmlTextWriter2, origin.skin);
			}
		}
		catch (Exception ex)
		{
			LogHelper.WriteException(ex, "SkinFileSave - 保存皮肤文件");
			return false;
		}
		return true;
	}

	public static bool SkinFileLoad(ref Origin origin, string fullName, bool isClone = false)
	{
		try
		{
			if (IsXml(fullName))
			{
				XmlSerializer xmlSerializer = new XmlSerializer(origin.skin.GetType());
				using XmlTextReader xmlReader = new XmlTextReader(fullName);
				SetSkinAll(ref origin, (Skin)xmlSerializer.Deserialize(xmlReader), isClone);
			}
		}
		catch (Exception ex)
		{
			LogHelper.WriteException(ex, "SkinFileLoad - 加载皮肤文件");
			return false;
		}
		return true;
	}

	private static void SetSkinAll(ref Origin origin, Skin skin, bool isClone = false)
	{
		Ped character = skin.Character;
		if (origin.Member == Main.Member.P2)
		{
			Main.ReBuildP2(Main.P2.Character, skin.ModelName, skin.IsAddonPed);
			character = Main.P2.Character;
			if (!Game.Player.Character.CurrentPedGroup.Contains(character) && Main.P2.Follow)
			{
				Main.P1.Character.CurrentPedGroup.Add(character, leader: false);
			}
		}
		else if (origin.Member == Main.Member.P1 && !isClone)
		{
			Main.ChangePlayerModel(skin.ModelName, skin.IsAddonPed);
			origin.BuildPedData(Game.Player.Character, Main.Member.P1, skin.IsAddonPed);
			character = Main.P1.Character;
			character.SetDefaultClothes();
		}
		else if (origin.Member == Main.Member.Clone && isClone)
		{
			if (Main.Clone.Character != null)
			{
				Main.Clone.Character.MarkAsNoLongerNeeded();
				Main.Clone.Character.Delete();
			}
			Ped ped = Main.CreatePed(skin.ModelName, skin.IsAddonPed);
			if (ped == null)
			{
				return;
			}
			Main.Clone.Character = ped;
			Main.Clone.Character.BlockPermanentEvents = true;
			Main.Clone.Character.IsPersistent = true;
			Main.Clone.BuildPedData(Main.Clone.Character, Main.Member.Clone, skin.IsAddonPed);
			character = Main.Clone.Character;
			character.SetDefaultClothes();
		}
		for (int i = 0; i < 12; i++)
		{
			if (skin.Components[i].action)
			{
				SkinHelper.SetPedComponentVariation(character, i, skin.Components[i].drawableId, skin.Components[i].textureId, skin.Components[i].paletteId);
			}
		}
		SkinHelper.ClearAllPedProps(character);
		for (int j = 0; j < 8; j++)
		{
			if (skin.Props[j].action)
			{
				SkinHelper.SetPedPropIndex(character, j, skin.Props[j].drawableId, skin.Props[j].textureId, skin.Props[j].attach);
			}
		}
		SkinHelper.ClearPedDecorations(character);
		for (int k = 0; k < 6; k++)
		{
			for (int l = 0; l < 4; l++)
			{
				if (skin.Tattoo[k][l].action)
				{
					SkinHelper.SetPedDecoration(character, skin.Tattoo[k][l].collectionName, skin.Tattoo[k][l].overlayName);
				}
			}
		}
		for (int m = 0; m < 6; m++)
		{
			for (int n = 0; n < 4; n++)
			{
				if (skin.Badge[m][n].action)
				{
					SkinHelper.SetPedDecoration(character, skin.Badge[m][n].collectionName, skin.Badge[m][n].overlayName);
				}
			}
		}
		if (skin.Head_Blend.action)
		{
			SkinHelper.SetPedHeadBlendData(character, skin.Head_Blend.shapeFirstID, skin.Head_Blend.shapeSecondID, skin.Head_Blend.shapeThirdID, skin.Head_Blend.skinFirstID, skin.Head_Blend.skinSecondID, skin.Head_Blend.skinThirdID, skin.Head_Blend.shapeMix, skin.Head_Blend.skinMix, skin.Head_Blend.thirdMix, skin.Head_Blend.isParent);
			for (int num = 0; num < 20; num++)
			{
				if (skin.Face_Feature[num].action)
				{
					SkinHelper.SetPedFaceFeature(character, num, skin.Face_Feature[num].featureValue);
				}
			}
			for (int num2 = 0; num2 < 13; num2++)
			{
				if (skin.Head_Overlay[num2].overlayAction)
				{
					SkinHelper.SetPedHeadOverlayValue(character, num2, skin.Head_Overlay[num2].overlayValue, skin.Head_Overlay[num2].opacity);
					if (skin.Head_Overlay[num2].colorAction)
					{
						SkinHelper.SetPedHeadOverlayColor(character, num2, skin.Head_Overlay[num2].colorType, skin.Head_Overlay[num2].firstColor, skin.Head_Overlay[num2].secondColor);
					}
				}
			}
			if (skin.Other_Colors.eyeAction)
			{
				SkinHelper.SetPedEyeColor(character, skin.Other_Colors.eyeColorId);
			}
			if (skin.Other_Colors.hairAction)
			{
				SkinHelper.SetPedHairColor(character, skin.Other_Colors.hairColorId, skin.Other_Colors.hairHighlightColorID);
			}
		}
		if (skin.Voice != null || skin.Voice != string.Empty)
		{
			character.SetVoice(skin.Voice);
		}
		origin.skin = skin;
		origin.skin.Character = character;
	}

	private static bool IsXml(string Path)
	{
		try
		{
			new XmlDocument().Load(Path);
			return true;
		}
		catch
		{
			return false;
		}
	}

	private static bool MakeFilenameValid(ref string filename)
	{
		if (filename == null)
		{
			filename = string.Empty;
		}
		if (filename.EndsWith("."))
		{
			filename = Regex.Replace(filename, "\\.+$", "");
		}
		if (filename.IndexOf('.') >= 0)
		{
			filename = filename.Substring(0, filename.IndexOf('.'));
		}
		if (filename.Length == 0)
		{
			filename = string.Empty;
		}
		if (filename.Length > 245)
		{
			filename = string.Empty;
		}
		if (filename.Replace(" ", "") == string.Empty)
		{
			filename = string.Empty;
		}
		char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
		foreach (char oldChar in invalidFileNameChars)
		{
			filename = filename.Replace(oldChar, '_');
		}
		if (filename != string.Empty)
		{
			return true;
		}
		return false;
	}

	public void GetComponentsValue()
	{
		foreach (int value in Enum.GetValues(typeof(PedComponents)))
		{
			Components[value].drawableId = SkinHelper.GetPedDrawableVariation(Character, value);
			Components[value].textureId = SkinHelper.GetPedTextureVariation(Character, value);
			Components[value].paletteId = SkinHelper.GetPedPaletteVariation(Character, value);
		}
	}

	public void GetPropsValue()
	{
		foreach (int value in Enum.GetValues(typeof(PedProps)))
		{
			Props[value].drawableId = SkinHelper.GetPedPropIndex(Character, value);
			Props[value].textureId = SkinHelper.GetPedPropTextureIndex(Character, value);
		}
	}

	public void GetComponentsVariableNumber()
	{
		foreach (int value in Enum.GetValues(typeof(PedComponents)))
		{
			Components[value].drawableNumber = SkinHelper.GetPedDrawableNumber(Character, value);
			ComponentsTextureData[value] = new int[Components[value].drawableNumber];
			for (int i = 0; i < Components[value].drawableNumber; i++)
			{
				ComponentsTextureData[value][i] = SkinHelper.GetPedTextureNumber(Character, value, i);
			}
		}
	}

	public void GetPropsVariableNumber()
	{
		foreach (int value in Enum.GetValues(typeof(PedProps)))
		{
			Props[value].drawableNumber = SkinHelper.GetPedPropDrawableNumber(Character, value);
			PropsTextureData[value] = new int[Props[value].drawableNumber];
			for (int i = 0; i < Props[value].drawableNumber; i++)
			{
				PropsTextureData[value][i] = SkinHelper.GetPedPropTextureNumber(Character, value, i);
			}
		}
	}

	public void GetHeadBlendFaceNumber()
	{
		Head_Blend.faceNumber = 0;
		for (int i = 0; i < 4; i++)
		{
			Head_Blend.faceNumber += SkinHelper.GetNumParentPedsOfType(i);
		}
	}

	public void GetHeadOverlayVariableNumber()
	{
		foreach (int value in Enum.GetValues(typeof(PedHeadOverlay)))
		{
			Head_Overlay[value].overlayNumber = SkinHelper.GetNumHeadOverlayValue(value);
		}
	}

	public void GetDecorationData(Decoration.Type type)
	{
		List<Decoration.Collection> list = new List<Decoration.Collection>();
		list = Decoration.Collection.GetCollectionList(type);
		switch (type)
		{
		case Decoration.Type.TYPE_TATTOO:
		{
			TattooData = new List<Decoration.Collection>[6];
			for (int j = 0; j < 6; j++)
			{
				TattooData[j] = new List<Decoration.Collection>();
				foreach (Decoration.Collection item in list)
				{
					Decoration.Collection collectionClassify = Decoration.Collection.GetCollectionClassify(item, Character.Gender, (Decoration.Zone)j);
					if (collectionClassify.overlay.Count > 0)
					{
						TattooData[j].Add(collectionClassify);
					}
				}
			}
			break;
		}
		case Decoration.Type.TYPE_BADGE:
		{
			BadgeData = new List<Decoration.Collection>[6];
			for (int i = 0; i < 6; i++)
			{
				BadgeData[i] = new List<Decoration.Collection>();
				foreach (Decoration.Collection item2 in list)
				{
					Decoration.Collection collectionClassify = Decoration.Collection.GetCollectionClassify(item2, Character.Gender, (Decoration.Zone)i);
					if (collectionClassify.overlay.Count > 0)
					{
						BadgeData[i].Add(collectionClassify);
					}
				}
			}
			break;
		}
		}
	}

	public void ClearDecoration(Decoration.Type type, int gid, Decoration.Zone zone = Decoration.Zone.ZONE_NONE)
	{
		if (type == Decoration.Type.TYPE_TATTOO)
		{
			if (zone == Decoration.Zone.ZONE_NONE)
			{
				SkinHelper.ClearPedDecorations(Character);
				for (int i = 0; i < 6; i++)
				{
					Tattoo[i][gid].collectionName = (Tattoo[i][gid].overlayName = string.Empty);
					Tattoo[i][gid].action = false;
				}
				for (int j = 0; j < 6; j++)
				{
					for (int k = 0; k < 4; k++)
					{
						if (k != gid)
						{
							SkinHelper.SetPedDecoration(Character, Tattoo[j][k].collectionName, Tattoo[j][k].overlayName);
						}
					}
				}
				for (int l = 0; l < 6; l++)
				{
					for (int m = 0; m < 4; m++)
					{
						SkinHelper.SetPedDecoration(Character, Badge[l][m].collectionName, Badge[l][m].overlayName);
					}
				}
			}
			if (zone < Decoration.Zone.ZONE_UNKNOWN)
			{
				Tattoo[(int)zone][gid].collectionName = (Tattoo[(int)zone][gid].overlayName = string.Empty);
				Tattoo[(int)zone][gid].action = false;
				SkinHelper.ClearPedDecorations(Character);
				for (int n = 0; n < 6; n++)
				{
					for (int num = 0; num < 4; num++)
					{
						if ((num == gid && n != (int)zone) || num != gid)
						{
							SkinHelper.SetPedDecoration(Character, Tattoo[n][num].collectionName, Tattoo[n][num].overlayName);
						}
					}
				}
				for (int num2 = 0; num2 < 6; num2++)
				{
					for (int num3 = 0; num3 < 4; num3++)
					{
						SkinHelper.SetPedDecoration(Character, Badge[num2][num3].collectionName, Badge[num2][num3].overlayName);
					}
				}
			}
		}
		if (type != Decoration.Type.TYPE_BADGE)
		{
			return;
		}
		if (zone == Decoration.Zone.ZONE_NONE)
		{
			SkinHelper.ClearPedDecorations(Character);
			for (int num4 = 0; num4 < 6; num4++)
			{
				Badge[num4][gid].collectionName = (Badge[num4][gid].overlayName = string.Empty);
				Badge[num4][gid].action = false;
			}
			for (int num5 = 0; num5 < 6; num5++)
			{
				for (int num6 = 0; num6 < 4; num6++)
				{
					if (num6 != gid)
					{
						SkinHelper.SetPedDecoration(Character, Badge[num5][num6].collectionName, Badge[num5][num6].overlayName);
					}
				}
			}
			for (int num7 = 0; num7 < 6; num7++)
			{
				for (int num8 = 0; num8 < 4; num8++)
				{
					SkinHelper.SetPedDecoration(Character, Tattoo[num7][num8].collectionName, Tattoo[num7][num8].overlayName);
				}
			}
		}
		if (zone >= Decoration.Zone.ZONE_UNKNOWN)
		{
			return;
		}
		Badge[(int)zone][gid].collectionName = (Badge[(int)zone][gid].overlayName = string.Empty);
		Badge[(int)zone][gid].action = false;
		SkinHelper.ClearPedDecorations(Character);
		for (int num9 = 0; num9 < 6; num9++)
		{
			for (int num10 = 0; num10 < 4; num10++)
			{
				if ((num10 == gid && num9 != (int)zone) || num10 != gid)
				{
					SkinHelper.SetPedDecoration(Character, Badge[num9][num10].collectionName, Badge[num9][num10].overlayName);
				}
			}
		}
		for (int num11 = 0; num11 < 6; num11++)
		{
			for (int num12 = 0; num12 < 4; num12++)
			{
				SkinHelper.SetPedDecoration(Character, Tattoo[num11][num12].collectionName, Tattoo[num11][num12].overlayName);
			}
		}
	}

	public List<WeaponData> GetWeaponsData()
	{
		Weaponry = new List<WeaponData>();
		List<uint> list = new List<uint>();
		uint hash = (uint)Character.Weapons.Current.Hash;
		foreach (WeaponHash value in Enum.GetValues(typeof(WeaponHash)))
		{
			if (Character.Weapons.HasWeapon(value))
			{
				list.Add((uint)value);
			}
		}
		foreach (uint item2 in list)
		{
			WeaponData item = new WeaponData
			{
				weaponComponent = new List<uint>(),
				InUse = ((hash == item2) ? true : false)
			};
			Character.Weapons.Select((WeaponHash)item2, equipNow: true);
			item.weaponHash = item2;
			item.ammo = Character.Weapons.Current.Ammo;
			item.ammoInClip = Character.Weapons.Current.AmmoInClip;
			item.tint = (int)Character.Weapons.Current.Tint;
			item.maxComponents = Character.Weapons.Current.MaxComponents;
			for (int i = 0; i < item.maxComponents; i++)
			{
				if (Character.Weapons.Current.IsComponentActive(Character.Weapons.Current.GetComponent(i)))
				{
					item.weaponComponent.Add((uint)Character.Weapons.Current.GetComponent(i));
				}
			}
			Weaponry.Add(item);
		}
		Character.Weapons.Select((WeaponHash)hash, equipNow: true);
		return Weaponry;
	}

	public void SetWeapons(List<WeaponData> _weaponry)
	{
		Character.Weapons.RemoveAll();
		foreach (WeaponData item in _weaponry)
		{
			Character.Weapons.Give((WeaponHash)item.weaponHash, item.ammo, equipNow: true, isAmmoLoaded: false);
			Character.Weapons.Current.AmmoInClip = item.ammoInClip;
			Character.Weapons.Current.Tint = (WeaponTint)item.tint;
			Character.Weapons.Select((WeaponHash)item.weaponHash, equipNow: true);
			for (int i = 0; i < item.weaponComponent.Count; i++)
			{
				Character.Weapons.Current.SetComponent((WeaponComponent)item.weaponComponent[i], on: true);
			}
		}
		foreach (WeaponData item2 in _weaponry)
		{
			if (item2.InUse)
			{
				Character.Weapons.Select((WeaponHash)item2.weaponHash, equipNow: true);
			}
		}
	}

	public static string[] GetAddonPedsLoadName()
	{
		string filename = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "\\Rockstar Games\\GTA V\\UserMods\\ap_m.xml";
		try
		{
			XmlDocument xmlDocument = new XmlDocument();
			xmlDocument.Load(filename);
			XmlNodeList xmlNodeList = xmlDocument.SelectNodes("/CPedModelInfo__InitDataList/InitDatas/Item");
			List<string> list = new List<string>();
			foreach (XmlNode item in xmlNodeList)
			{
				list.Add(item["Name"].InnerText);
			}
			return list.ToArray();
		}
		catch (Exception)
		{
			UI.Notify("Could not read AddonPeds XML list.");
		}
		return new string[0];
	}

	public static void TryConvertAddonPedName(ref string name)
	{
		string numHash = name;
		string[] addonPedsLoadName = GetAddonPedsLoadName();
		if (addonPedsLoadName != null && numHash != null && TestStringToInt(numHash))
		{
			numHash = Array.Find(addonPedsLoadName, n => Origin.GetHash(n) == Convert.ToUInt32(numHash));
		}
		if (numHash != null || numHash != string.Empty)
		{
			name = numHash;
		}
	}

	private static bool TestStringToInt(string str)
	{
		try
		{
			Convert.ToUInt32(str);
			return true;
		}
		catch
		{
			return false;
		}
	}
}
